#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import string
import trans
from settings import UPLOAD_DIRECTORY


def transliteration(s):
    """
    Транстилерация строки
    — заменяет символы пробела на символ -
    """
    s = s.encode('trans')
    symbols = string.punctuation
    name, ext = os.path.splitext(s)
    symbols = symbols.replace('.',' ')
    table = string.maketrans(symbols, "-"*len(symbols))
    name = str(name).translate(table)
    return "%s%s" % (name, ext)


def generic_upload_to(instance, filename, relat_field_name=None):
    """
    Загружает файл в папку /media/[UPLOAD_DIRECTORY]/[APP_LABEL]/имя_файла
    форматирует имя файла переводя его в транслит, заменяя символы пробела на _

    relat_field_name - название поля связывающего с родительским, в путь сохранения будет подставлен родительский id
    """
    path_templ = UPLOAD_DIRECTORY+'/%s/%s'
    path_templ_args = [instance._meta.app_label, instance.__class__.__name__.lower()]
    # связь с родительской таблицей
    if relat_field_name and hasattr(instance, relat_field_name):
        path_templ+='/%s'
        path_templ_args.append(getattr(instance, '%s_id' % relat_field_name))
    upload_to = path_templ % tuple(path_templ_args)
    return u'%s/%s' % (upload_to, transliteration(filename))


def combine(objs1, objs2, *args, **kwargs):
    """
    Объединяет объекты по признакам

    objs1 - связываемый
    objs2 - будет добавлен в objs1.objs2_name в виде списка объектов

    limit максимальное количество присоединенных объектов

    *args может быть списком кортежей
    если имена атрибутов различны. Первый элемент кортежа - имя атрибута первой модели,
    второй элементо соответственно имя атрибута второй.

    Например:
    - Признак(Модель, по родительской связи(ям))
     - Модель1
     - Модель2

    print Модель1.model2_name
    [<Модель2>, <Модель2>, <Модель2> ...]
    """
    limit = kwargs.get('limit')

    if any(objs1) and any(objs2):
        signs = [] # собираем признаки
        for sign in args:
            attr1, attr2 = sign if any(sign) and not isinstance(sign, basestring) else (sign, sign)
            # проверяем у первых объектов наличие этих атрибутов
            if hasattr(objs1[0], attr1) and hasattr(objs2[0], attr2):
                signs.append((attr1, attr2,))
            else:
                raise ValueError('Unknown attribute name `%s` or `%s`' % (attr1, attr2))

        if signs:
            # раскладываем объекты по признакам
            dct = {}
            for obj2 in objs2:
                key = tuple(map(lambda s: getattr(obj2, s[1]), signs))
                if key in dct:
                    if limit and len(dct[key]) >= limit: continue
                    dct[key].append(obj2)
                else:
                    dct[key] = [obj2]

            # присваиваем значения
            for obj1 in objs1:
                key = tuple(map(lambda s: getattr(obj1, s[0]), signs))
                if key in dct:
                    attr_name = dct[key][0].__class__.__name__.lower()
                    setattr(obj1, attr_name, dct[key])
    return objs1